﻿using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.IO.Ports;
using System.Timers;
using System.Windows;
using System.Windows.Controls;
using System.Linq;
using Heroius.Extension;
using System.Text;

namespace Ryder
{
    /// <summary>
    /// MainWindow.xaml 的交互逻辑
    /// </summary>
    public partial class MainWindow : Window, INotifyPropertyChanged
    {

        public MainWindow()
        {
            InitializeComponent();

            UpdatePorts();

            sp = new SerialPort();
            sp_i = new PortInfo(sp);

            recevier = new Timer(Properties.Settings.Default.RequestInterval);
            recevier.Elapsed += Recevier_Elapsed;
            Send[0] = 0x11;
            Send[1] = 0x01;
            Send[2] = 0x01;
            Send[3] = 0xED;
            bigBuffer = new List<byte>();

            Messages = new ObservableCollection<string>();

            DataContext = this;
        }

        public event PropertyChangedEventHandler PropertyChanged;
        public void RaisePropertyChangedEvent(string PropertyName)
        {
            PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(PropertyName));
        }

        /// <summary>
        /// 发送帧模板
        /// </summary>
        byte[] Send = new byte[4];
        /// <summary>
        /// 运行时标记，切换发送和接收状态
        /// </summary>
        bool time2Read;
        /// <summary>
        /// 运行时缓存，保留尚未处理的已接收数据
        /// </summary>
        List<byte> bigBuffer;
        /// <summary>
        /// 运行时计数器，记录等待返回帧的经过周期
        /// </summary>
        int continueCounter;

        /// <summary>
        /// 时钟
        /// </summary>
        Timer recevier;
        /// <summary>
        /// 串口
        /// </summary>
        SerialPort sp;
        /// <summary>
        /// 串口配置实体
        /// </summary>
        PortInfo sp_i;
        /// <summary>
        /// 消息
        /// </summary>
        public ObservableCollection<string> Messages { get; set; }

        public bool Connectable { get { return CmbPorts.SelectedIndex >= 0; } }
        public bool Connected { get { return sp.IsOpen; } }

        private void Recevier_Elapsed(object sender, ElapsedEventArgs e)
        {
            Dispatcher.Invoke(new Action(() =>
            {
                try
                {
                    if (time2Read)
                    {
                        continueCounter++;
                        int count = sp.BytesToRead;
                        if (count > 0)
                        {
                            byte[] buffer = new byte[count];
                            sp.Read(buffer, 0, count);
                            bigBuffer.AddRange(buffer);
                            AddMessage($"Recieve: {buffer.Select(b => b.ToString("x")).Merge(" ")}");
                            if (bigBuffer.Count > 1)
                            {
                                var len = bigBuffer[1];
                                if (bigBuffer.Count >= len + 3)
                                {
                                    if (bigBuffer[0] == 0x16)
                                    {
                                        var cnt = (bigBuffer[1] - 2) / 2;
                                        StringBuilder builder = new StringBuilder();
                                        for (int i = 0; i < cnt; i++)
                                        {
                                            var idx = 3 + i * 2;
                                            var rev = new byte[] { bigBuffer[idx + 1], bigBuffer[idx] };
                                            builder.Append($"{Convert.ToChar(Convert.ToInt32('A')+i)}:{BitConverter.ToInt16(rev, 0)} ");
                                        }
                                        AddMessage(builder.ToString());
                                    }
                                    // error handler

                                    //清理
                                    bigBuffer.Clear();
                                    continueCounter = 0;
                                    time2Read = false;
                                    return;
                                }
                            }
                        }
                        if (continueCounter > Properties.Settings.Default.TimeoutCircle)
                        {
                            //清理
                            bigBuffer.Clear();
                            continueCounter = 0;
                            AddMessage("Timeout: 在等待时限内未接收到足够数据");
                            time2Read = false;
                        }
                    }
                    else
                    {
                        sp.Write(Send, 0, 4);
                        time2Read = true;
                        AddMessage($"Send: {Send.Select(b => b.ToString("x")).Merge(" ")}");
                    }
                }
                catch(Exception ex)
                {
                    //do sth
                    AddMessage($"Err: {ex.Message}");
                }
            }), null);
        }

        void AddMessage(string msg)
        {
            Messages.Add(msg);
            if (Messages.Count > Properties.Settings.Default.MsgLimit)
            {
                Messages.RemoveAt(0);
            }
        }

        private void CmbPorts_SelectionChanged(object sender, SelectionChangedEventArgs e)
        {
            RaisePropertyChangedEvent("Connectable");
        }

        private void Refresh_Click(object sender, RoutedEventArgs e)
        {
            UpdatePorts();
            Messages.Clear();
        }

        public void UpdatePorts()
        {
            var ports = SerialPort.GetPortNames();
            CmbPorts.Items.Clear();
            foreach (var item in ports)
            {
                CmbPorts.Items.Add(item);
            }
            RaisePropertyChangedEvent("Connectable");
        }

        private void Set_Click(object sender, RoutedEventArgs e)
        {
            new SetWindow(sp_i).ShowDialog();
        }

        private void Conn_Click(object sender, RoutedEventArgs e)
        {
            if (Connected)
            {
                BtnConn.Content = "连接";
                recevier.Stop();
                sp.Close();
            }
            else
            {
                BtnConn.Content = "断开";
                //重置运行时状态
                time2Read = false;
                bigBuffer.Clear();
                continueCounter = 0;

                sp.PortName = CmbPorts.SelectedValue.ToString();
                //
                sp.Open();
                recevier.Start();

            }
            RaisePropertyChangedEvent("Connected");
        }


    }
}
